﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Propertys
{
   public class bakteria
   {
       public int numOfPop;
       public char empty;
       public char pease;
       public char canib;
       public int for_born;
       public int for_die_alone;
       public int for_die;

   }
}


namespace Evolution
{
    public class Bakteria
    {
        protected char x;
        public Bakteria(char x)
        {
            this.x = x;           
        }

        public virtual int Gotnum()
        {
            return 0;
        }

        public virtual void DoStep(byte i, byte j, Evolution.Bakteria[,] popul, Propertys.bakteria prop)
        {
        }

        public virtual void Draw()
        {
            Console.Write(x);
        }
    }

    class Empty:Bakteria
    {
        public Empty(char x):base(x)
        {          
        }

        public override int Gotnum()
        {
            return 0;
        }

        public override void DoStep(byte i, byte j, Evolution.Bakteria[,] popul, Propertys.bakteria prop)
        {
            byte peace = 0;
            byte canib = 0;
            for (int m = i - 1; m <= i + 1; m++)
                for (int n = j - 1; n <= j + 1; n++)
                {
                    switch (popul[m, n].Gotnum())
                    {
                        case 2:
                            canib++;
                            break;
                        case 1:
                            peace++;
                            break;
                    }                 
                }
            if (peace >=prop.for_born) popul[i, j] = new Peaseful(prop.pease);
            if (canib >= prop.for_born) popul[i, j] = new Canibal(prop.canib);
        }
            
        
        
    }

    class Peaseful:Bakteria
    {
        public Peaseful(char x):base(x)
        {
        }

        public override int Gotnum()
        {
            return 1;
        }

        public override void DoStep(byte i, byte j, Evolution.Bakteria[,] popul, Propertys.bakteria prop)
        {
            byte all = 0;
            byte thus = 0;
            for (int m = i - 1; m <= i + 1; m++)
                for (int n = j - 1; n <= j + 1; n++)
                {
                    switch (popul[m, n].Gotnum())
                    {
                        case 2:
                            all++;
                            break;
                        case 1:
                            all++;
                            thus++;
                            break;
                    }                 
                }
            if (thus - 1 < prop.for_die_alone) popul[i, j] = new Empty(prop.empty);
            if (all - 1 > 8 - prop.for_die) popul[i, j] = new Empty(prop.empty);
        
        }

    }

    class Canibal:Bakteria
    {
        public Canibal(char x): base(x)
        {
        }

        public override int Gotnum()
        {
            return 2;
        }

        public override void DoStep(byte i, byte j, Evolution.Bakteria[,] popul, Propertys.bakteria prop)
        {
            byte all = 0;
            byte thus = 0;
            for (int m = i - 1; m <= i + 1; m++)
                for (int n = j - 1; n <= j + 1; n++)
                {
                    bool hungry = true;
                    switch (popul[m, n].Gotnum())
                    {
                        case 1:
                            if (hungry)
                            {
                                popul[m, n] = new Empty(prop.empty);
                                hungry = false;
                            }
                            else
                                all++;
                            break;
                        case 2:
                            all++;
                            thus++;
                            break;
                    }                    
                }
            if (thus - 1 < prop.for_die_alone) popul[i, j] = new Empty(prop.empty);
            if (all - 1 > 8 - prop.for_die) popul[i, j] = new Empty(prop.empty);
        }

    }
}

namespace ConsoleApplication1
{
    class Program
    {
        
        static void Main(string[] args)
        {

            //MAIN CONSOLE MENU
            Console.WindowHeight = 35;
            string path = "settings.ini";
            Propertys.bakteria prop = new Propertys.bakteria();
            bool chage = false;
            ConsoleKeyInfo key;
            if (File.Exists(path))
            {
                using (StreamReader sr = new StreamReader(path))
                {
                    Console.WriteLine("                   Меню");
                    Console.WriteLine("____________________________________________");
                    Console.WriteLine("Парамтры жизни:");
                    prop.numOfPop=Convert.ToInt16(sr.ReadLine());
                    Console.WriteLine("Количество бактерий : {0} из 900 ", prop.numOfPop);
                    prop.empty = Convert.ToChar(sr.ReadLine());
                    Console.WriteLine("Пустые места обозначаються '{0}'", prop.empty);
                    prop.pease = Convert.ToChar(sr.ReadLine());
                    Console.WriteLine("Мирные бактерии обозначаються '{0}'", prop.pease);
                    prop.canib = Convert.ToChar(sr.ReadLine());
                    Console.WriteLine("Хищьные бактерии обозначаються '{0}'", prop.canib);
                    prop.for_born = Convert.ToInt16(sr.ReadLine());
                    Console.WriteLine("Вокруг должно быть {0} бактерий чтобы появилась новая", prop.for_born);
                    prop.for_die_alone = Convert.ToInt16(sr.ReadLine());
                    Console.WriteLine("Вокруг должно быть меньше {0} таких же бактерий чтобы бактерия умерла", prop.for_die_alone);
                    prop.for_die = Convert.ToInt16(sr.ReadLine());
                    Console.WriteLine("Вокруг должно быть меньше {0} пустых мест чтобы бактерия умерла", prop.for_die);
                    Console.WriteLine();
                    Console.WriteLine("Нажмите ЛК для начала работы или Пробел чтобы изменить настройки.");

                }
                key = Console.ReadKey();
                if (key.Key == ConsoleKey.Spacebar) chage = true;
            }
            if ((!File.Exists(path)) || chage)
            {
                if (File.Exists(path))
                {
                    File.Delete(path);
                }
                using (StreamWriter sw = new StreamWriter(path))
                {
                    Console.Clear();
                    Console.WriteLine("Редактирование параметров:");
                    Console.WriteLine("Введите плотность популяции (от 0 до 900):");
                    prop.numOfPop = Convert.ToInt16(Console.ReadLine());
                    sw.WriteLine(prop.numOfPop);
                    Console.WriteLine("Как будут обозначаться пустые места?");
                    prop.empty = Convert.ToChar(Console.ReadLine());
                    sw.WriteLine(prop.empty);
                    Console.WriteLine("Как будут обозначаться мирные бактерии?");
                    prop.pease = Convert.ToChar(Console.ReadLine());
                    sw.WriteLine(prop.pease);
                    Console.WriteLine("Как будут обозначаться хищьники?");
                    prop.canib = Convert.ToChar(Console.ReadLine());
                    sw.WriteLine(prop.canib);
                    Console.WriteLine("Сколько необходимо клеток вокруг, чтобы родилась новая?");
                    prop.for_born = Convert.ToInt16(Console.ReadLine());
                    sw.WriteLine(prop.for_born);
                    Console.WriteLine("Клетка умрёт, если таких же клеток вокрут будет меньше чем");
                    prop.for_die_alone = Convert.ToInt16(Console.ReadLine());
                    sw.WriteLine(prop.for_die_alone);
                    Console.WriteLine("Клетка умрёт, если свободных мест вокруг будет меньше чем");
                    prop.for_die = Convert.ToInt16(Console.ReadLine());
                    sw.WriteLine(prop.for_die);
                    Console.WriteLine("Нажмите Enter для продолжения");
                    Console.ReadLine();
                }
            }


            Console.Clear();
            Console.WriteLine("Population");
            Random rand = new Random();
            byte size = 30;
            Evolution.Bakteria[,] population = new Evolution.Bakteria[size + 2, size + 2];
            byte [,] pop_matrx = new byte [size+2,size+2];
            

            //CREATION & FIRTS OUTPUT
            for (int i = 0; i < size + 2; i++)
                for (int j = 0; j < size + 2; j++)
                {
                    pop_matrx[i, j] = 0;
                    population[i, j] = new Evolution.Empty(prop.empty);
                }

            for (int i = 1; i <= prop.numOfPop; i++)
            {
                int index = Convert.ToInt16(Math.Round(rand.NextDouble() * size * size));
                pop_matrx[(index / size)+1, (index % size)+1]= Convert.ToByte(Math.Round(rand.NextDouble())+1);
            }

            for (int i = 1; i < size + 1; i++)
            {
                for (int j = 1; j < size + 1; j++)
                {
                    switch (pop_matrx[i, j])
                    {
                        case 1:
                            population[i, j] = new Evolution.Peaseful(prop.pease);
                            break;
                        case 2:
                            population[i, j] = new Evolution.Canibal(prop.canib);
                            break;
                    }
                    population[i, j].Draw();
                }
                Console.WriteLine();     
            }


            //EVOLUTION 
            key = Console.ReadKey();
            while (key.Key == ConsoleKey.Spacebar)
            {
                Console.Clear();
                Console.WriteLine("Evolution");
                for (byte i = 1; i < size + 1; i++)
                {
                    for (byte j = 1; j < size + 1; j++)
                    {
                        population[i, j].DoStep(i, j, population, prop);
                        population[i, j].Draw();
                    }
                    Console.WriteLine();
                }
                key = Console.ReadKey();
            }
        }
    }
}
